#include "SDL/SDL.h"

#include "mainsonic.h"
#include "video.h"
#include "videoext.h"
#include "object.h"
#include "plcnew.h"
#include "objectsystemNEWER.h"
#include "paletteNEWER.h"
#include "zoneNEWER.h"
#include "draw.h"
#include "plc.h"
#include "camera.h"
#include "sprite.h"
#include "sonic.h"
#include "joypad.h"
#include "collision.h"
#include "anim.h"
#include "hud.h"
#include "debug.h"
#include "decompress.h"
#include "misc.h"

#include <stdio.h>



#define LONG(hi,lo) (hi<<16)+lo
#define HI(val) (val<<16)
#define LO(val) val
#define LONGTOWORD LEFTRADIXLONG
#define LEFTRADIXLONG(val) ((val & 0xFFFF0000) >> 16) 
#define SWAPWORD(val) (((val&0x00FF)<<8)+((val&0xFF00)>>8))


//extern zone currentZone;
extern object* player;
extern object* objects;
extern layerpalette backgroundpal;
extern layerpalette foregroundpal;

extern byte Nem_TitleCard[];

extern word *vRam;
extern word *fgRam;

word *vRamptr=(word*)vRam; 
word *fgRamptr=(word*)fgRam; 
extern long v_hscrolltablebuffer[];
byte *v_spritetablebuf=(byte*)getSpriteTableBuf();
extern byte v_sgfx_buffer[];
extern long v_screenposx;
extern long v_screenposy;
extern word v_lookshift;

extern word v_anglebuffer;
extern word FFFFF76A;

word v_framecount;

extern byte f_scorecount;
extern byte f_ringcount;
extern byte f_timecount;

extern word v_pfade_start;
extern word v_pfade_size;

extern byte v_oscillate[];

long v_vbla_count;
#define v_vbla_word (v_vbla_count & 0x0000FFFF)
#define v_vbla_byte (v_vbla_count & 0x000000FF)

//--the following variables/memory locations are buffered/copies transferred during a vblank..--
//--this is so the scroll engine can communicate with the drawing engine------------------------
extern word v_bgscroll1, v_bgscroll2, v_bgscroll3;
extern word scrollflagBuf1, scrollflagBuf2, scrollflagBuf3;

extern signed long FFFFF70C;   //bg layer sect 1 y pos
extern signed long FFFFF714;   //bg layer sect 2 y pos
extern signed long FFFFF708;   //bg layer sect 1 x pos
extern signed long FFFFF710;   //bg layer sect 2 x pos
extern signed long FFFFF718;   //bg layer sect 3 x pos
extern signed long FFFFF71C;   //bg layer sect 3 y pos
extern long screenposxBuf1, screenposyBuf1;
extern long FFFFFF18, FFFFFF1C, FFFFFF20, FFFFFF24, FFFFFF28, FFFFFF2C;

extern word v_scrposy_dup, FFFFF618;
extern word v_scrposx_dup, FFFFF61C;
extern word FFFFF61E, FFFFF620;
//-----------------------------------------------------------------------------------------------

bool keys[0xFFFF];
extern byte v_jpadhold1;
int mousex,mousey; 
bool mouseleft=false, mouseright=false;

bool quit=false;


byte v_zone;
byte v_act;
byte f_restart;
    
void DrawScene();
SDL_Surface *screen;

#define singleFrame (1000/60)  //60 fps
extern long clock;
extern long delayTime;
extern long timeFrame;

bool executionPause = false;

int main( int argc, char** argv ) 
{   
    
    initVideoExt();
    
    SDL_Init( SDL_INIT_VIDEO ); 
    clock = SDL_GetTicks();
    screen = SDL_SetVideoMode( WINDOWWIDTH, WINDOWHEIGHT, 32, SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_HWPALETTE | SDL_ASYNCBLIT | SDL_HWACCEL );        
     
    pcPatterns();
    pcObjectMethods();
    pcLevelBounds();
    pcScrolling();
    pcSonic();
    pcStartLocations();

    //GM_Level:				; XREF: GameModeArray
    //bset	#7,(v_gamemode).w ; add $80 to screen mode (for pre level sequence)
    //tst.w	(f_demo).w
    //bmi.s	Level_NoMusicFade
    //move.b	#bgm_Fade,d0
    //bsr.w	PlaySound_Special ; fade out music
    //Level_NoMusicFade:
    //bsr.w	ClearPLC
    //bsr.w	PaletteFadeOut
    //tst.w	(f_demo).w	; is an ending sequence demo running?
    //bmi.s	Level_ClrRam	; if yes, branch
    

    //		disable_ints
    //		locVRAM	$B000
    //		lea	(Nem_TitleCard).l,a0 ; load title card patterns
    //		bsr.w	NemDec
    GM_Level();
    return 0;
}

int GM_Level()
{   
    v_zone=0;
    v_act=0;

    do
    {
    NemDec((byte*)&Nem_TitleCard,(byte*)&vRam[0xB000/2]);
 
    //		enable_ints     
    //moveq	#0,d0
    //move.b	(v_zone).w,d0
    //lsl.w	#4,d0
    //lea	(LevelHeaders).l,a2
    //lea	(a2,d0.w),a2
    //moveq	#0,d0
    //move.b	(a2),d0
    //beq.s	loc_37FC
    //bsr.w	AddPLC		; load level patterns

    #define plcid_Main 0
    NewPLC(plcid_Main);
    RunAllPLCs();    
           
    ClearPLC();
    //bsr.w	PaletteFadeOut
    //vvvv the value of '4' in AddPLC is actually the index of main patterns for GHZ, -should- be grabbed from LevelHeaders...
    AddPLC(4); 
 

    #define plcid_Main2 1
    //moveq	#plcid_Main2,d0       TODO: ALSO LOAD STANDARD PATTERNS                        
    //bsr.w	AddPLC		
    AddPLC(plcid_Main2);
    
    /* THEN HUGE LIST OF CLEAR/INITIALIZE LEVEL VARIABLES..., NOT NEEDED YET */
    //Level_ClrRam:
    //lea	(v_objspace).w,a1
    //moveq	#0,d0
    long *objSpace = (long*)&objects[0];

    //move.w	#$7FF,d1
    signed short objCount = 0x7FF;

    //Level_ClrObjRam:
    //move.l	d0,(a1)+
    //dbf	d1,Level_ClrObjRam ; clear object RAM
    for (;objCount>=0;objCount--)
        (*objSpace++) = 0;

    //lea	($FFFFF628).w,a1
    //moveq	#0,d0
    //move.w	#$15,d1
    //Level_ClrVars1:
    //move.l	d0,(a1)+
    //dbf	d1,Level_ClrVars1 ; clear misc variables

    //lea	(v_screenposx).w,a1
    //moveq	#0,d0
    long *screenSpace = (long*)&v_screenposx;

    //move.w	#$3F,d1
    signed short screenCount = 0x3F;

    //Level_ClrVars2:
    //move.l	d0,(a1)+
    //dbf	d1,Level_ClrVars2 ; clear misc variables
    for (;screenCount>=0; screenCount--)
        (*screenSpace++) = 0;


    //lea	(v_oscillate+2).w,a1
    //moveq	#0,d0
    long *oscSpace = (long*)(&v_oscillate[0]+2);
    
    //move.w	#$47,d1
    signed short oscCount = 0x47;

    //Level_ClrVars3:
    //move.l	d0,(a1)+
    //dbf	d1,Level_ClrVars3 ; clear object variables
    for (;oscCount>=0; oscCount--)
        (*oscSpace++) = 0;

    //disable_ints
    //bsr.w	ClearScreen

    /* CODE FOR LOAD THE PROPER SONIC PALETTE.. */
    PalLoad2(palid_Sonic);

    /* CODE FOR PLAY THE PROPER BGM MUSIC */

    /* TITLE CARD LOOP (ALSO WHERE ALL PLCS FINALLY EXECUTED, INCLUDING THE RECENTLY CREATED FOR THE TITLE CARD PATTERNS) */
    #define id_TitleCard 0x34
    //move.b	#id_TitleCard,(v_objspace+$80).w ; load title card object
    objects[2].ID = id_TitleCard;
    
    signed short cardX;
    do
    {
        //Level_TtlCardLoop:
        //move.b	#$C,(v_vbla_routine).w
        //v_vbla_routine = 0xC;

        //bsr.w	WaitForVBla
        WaitForVBla();

        //jsr	ExecuteObjects
        ExecuteObjects();

        //jsr	BuildSprites
        BuildSprites();

        //bsr.w	RunPLC
        RunAllPLCs();

        //move.w	(v_objspace+$108).w,d0
        //cmp.w	(v_objspace+$130).w,d0 ; has title card sequence finished?
        cardX = objects[4].X;
        //DrawScene();

        //bne.s	Level_TtlCardLoop ; if not, branch
    }   while (cardX != getobjvariableword(0x30, objects[4]));

    //tst.l	(v_plc_buffer).w ; are there any items in the pattern load cue?
    //bne.s	Level_TtlCardLoop ; if yes, branch
     
    RunAllPLCs();

    //jsr Hud_Base              ; load basic HUD gfx
    Hud_Base();

    //moveq	#palid_Sonic,d0
    //bsr.w	PalLoad1	; load Sonic's palette
    PalLoad1(palid_Sonic);

    LevelSizeLoad(v_zone);

    DeformLayers(v_zone);

    //bset	#2,(v_bgscroll1).w
    v_bgscroll1 = v_bgscroll1 | 4;

    LevelDataLoad();
    LoadTilesFromStart();
    //jsr	FloorLog_Unk
    ColIndexLoad(v_zone);
    //bsr.w	LZWaterFeatures

    //move.b	#id_SonicPlayer,(v_objspace).w ; load Sonic object
    #define id_SonicPlayer 1
    objects[0].ID=1;
    
    //tst.w	(f_demo).w
    //bmi.s	Level_ChkDebug
    //move.b	#id_HUD,(v_objspace+$40).w ; load HUD object
    #define id_HUD 0x21
    objects[1].ID=id_HUD;

    /*
    Level_ChkDebug:
		tst.b	(f_debugcheat).w ; has debug cheat been entered?
		beq.s	Level_ChkWater	; if not, branch
		btst	#bitA,(v_jpadhold1).w ; is A button held?
		beq.s	Level_ChkWater	; if not, branch
		move.b	#1,(f_debugmode).w ; enable debug mode

    Level_ChkWater:
		move.w	#0,(v_jpadhold2).w
		move.w	#0,(v_jpadhold1).w
		cmpi.b	#id_LZ,(v_zone).w ; is level LZ?
		bne.s	Level_LoadObj	; if not, branch
		move.b	#id_WaterSurface,(v_objspace+$780).w ; load water surface object
		move.w	#$60,(v_objspace+$780+obX).w
		move.b	#id_WaterSurface,(v_objspace+$7C0).w
		move.w	#$120,(v_objspace+$7C0+obX).w
    */


    /* CODE FOR DEBUG/DEMO MODE ACTIVATE */

    //v_jpadhold2 = 0;    init joypad buffers
    //v_jpadhold1 = 0;

    //jsr	ObjPosLoad
    ExecuteObjects();
    BuildSprites();

    //tst.b	(v_lastlamp).w	; are you starting from	a lamppost?
    //bne.s	Level_SkipClr	; if yes, branch
    //if (v_lastlamp == 0)
    //{
        //move.w	d0,(v_rings).w	; clear rings
    //    v_rings = 0;

	//move.l	d0,(v_time).w	; clear time
    //    v_time = 0;

	//move.b	d0,(v_lifecount).w ; clear lives counter
    //    v_lifecount = 0;
    //}

    //Level_SkipClr:
    //move.b	d0,(f_timeover).w
    //f_timeover = 0;

    //move.b	d0,(v_shield).w	; clear shield
    //v_shield = 0;

    //move.b	d0,(v_invinc).w	; clear invincibility
    //v_invinc = 0;

    //move.b	d0,(v_shoes).w	; clear speed shoes
    //v_shoes = 0;

    //move.b	d0,($FFFFFE2F).w
    //move.w	d0,(v_debuguse).w
    //v_debuguse = 0;

    //move.w	d0,(f_restart).w
    f_restart = 0;

    //move.w	d0,(v_framecount).w
    v_framecount = 0;

    /* CODE FOR CLEAR A BUNCH OF LEVEL COUNTERS */
    //bsr.w	OscillateNumInit
    OscillateNumInit();

    //move.b	#1,(f_scorecount).w ; update score counter
    //move.b	#1,(f_ringcount).w ; update rings counter
    //move.b	#1,(f_timecount).w ; update time counter
    f_scorecount = 1;      //enable
    f_ringcount = 1;       //game
    f_timecount = 1;       //counters

    /* .........*/
    
    
    /* LOAD DEMO MODE DATA */

    /* ADDITIONAL CODE FOR LOAD SEPARATE WATER PALETTES */
    
    /* CODE FOR DELAY TO ALLOW TITLE CARD TO DISPLAY */
    
       //Level_Delay:
       //move.w	#3,d1
       for (signed short delayTime = 3; delayTime>=0; delayTime--)
       {
           //Level_DelayLoop:
           //move.b	#8,(v_vbla_routine).w
       
           //bsr.w	WaitForVBla
           WaitForVBla();
       
       }   //dbf	d1,Level_DelayLoop

    /* FADE IN TO LEVEL PALETTE COLORS */
    //move.w	#$202F,(v_pfade_start).w ; fade in 2nd, 3rd & 4th palette lines
    v_pfade_start = 0x20;
    v_pfade_size = 0x2F;
    
    //bsr.w	PalFadeIn_Alt
    PalFadeIn_Alt();
    
    //tst.w	(f_demo).w	; is an ending sequence demo running?
        //bmi.s	Level_ClrCardArt ; if yes, branch
    //PaletteNoFade();    //NO FADING YET...


    /* CODE FOR SET TITLE CARD TO MOVE AWAY */
    //addq.b	#2,(v_objspace+$80+obRoutine).w ; make title card move
    objects[2].Routine = objects[2].Routine + 2;

    //addq.b	#4,(v_objspace+$C0+obRoutine).w
    objects[3].Routine = objects[3].Routine + 4;

    //addq.b	#4,(v_objspace+$100+obRoutine).w
    objects[4].Routine = objects[4].Routine + 4;

    //addq.b	#4,(v_objspace+$140+obRoutine).w
    objects[5].Routine = objects[5].Routine + 4;
		
    //bra.s	Level_StartGame
    timeFrame = 0;
    
    //While the user hasn't quit 
    while( (quit == false) && (f_restart == 0)) 
    { 
        //bsr.w	PauseGame

	//move.b	#8,(v_vbla_routine).w

	//bsr.w	WaitForVBla
        WaitForVBla();

	//addq.w	#1,(v_framecount).w ; add 1 to level timer
        v_framecount = v_framecount + 1;

	//bsr.w	MoveSonicInDemo

	//bsr.w	LZWaterFeatures
       
        //jsr	ExecuteObjects
        ExecuteObjects();

SLX_S1DebugInfo();

	//if Revision=0
	//else
	//tst.w   (f_restart).w
        if (f_restart == 0) {
        //bne     GM_Level

	
	//endc
	//tst.w	(v_debuguse).w	; is debug mode being used?
	//bne.s	Level_DoScroll	; if yes, branch
	//cmpi.b	#6,(v_player+obRoutine).w ; has Sonic just died?
	//bhs.s	Level_SkipScroll ; if yes, branch
        
        //Level_DoScroll:
        //bsr.w	DeformLayers
        DeformLayers(v_zone);

	//Level_SkipScroll:
	//jsr	BuildSprites
        BuildSprites();

	//jsr	ObjPosLoad
        ObjPosLoad();

	//bsr.w	PaletteCycle
        PaletteCycle();
        
	//bsr.w	RunPLC
        RunAllPLCs();

	//bsr.w	OscillateNumDo
        OscillateNumDo();

	//bsr.w	SynchroAnimate
        SynchroAnimate();

	//bsr.w	SignpostArtLoad
        SignpostArtLoad();

		/*cmpi.b	#id_Demo,(v_gamemode).w
		beq.s	Level_ChkDemo	; if mode is 8 (demo), branch
		if Revision=0
		tst.w	(f_restart).w	; is the level set to restart?
		bne.w	GM_Level	; if yes, branch
		else
		endc
		cmpi.b	#id_Level,(v_gamemode).w
		beq.w	Level_MainLoop	; if mode is $C (level), branch*/

        //DrawScene();

        SDL_Event event;
        while (executionPause == true)
        {
           SDL_PollEvent(&event);
           if( event.type == SDL_QUIT ) 
           { 
               SDL_Quit();

               //Quit the program 
               return 0;
           }
           if ( event.type == SDL_KEYDOWN )
           {
               if ( event.key.keysym.sym == SDLK_ESCAPE ) { SDL_Quit(); return 0; }
               else if (event.key.keysym.sym == SDLK_RETURN ) { executionPause = false; }               else { keys[event.key.keysym.sym]=true; }
           }
        }
        //While there's an event to handle 
        while( SDL_PollEvent( &event ) ) 
        { 
              //DisplaySprite(objects[0]);
                
               if( event.type == SDL_QUIT ) 
               { 
                   //Quit the program 
                   quit = true; 
               }
               if ( event.type == SDL_KEYDOWN )
               {
                   if ( event.key.keysym.sym == SDLK_ESCAPE ) { quit=true; }
                   else if (event.key.keysym.sym == SDLK_RETURN ) { executionPause = false; }
                   else if (event.key.keysym.sym == SDLK_F1 ) { screen = SDL_SetVideoMode( WINDOWWIDTH, WINDOWHEIGHT, 32, SDL_FULLSCREEN | SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_HWPALETTE | SDL_ASYNCBLIT | SDL_HWACCEL ); }                   else if (event.key.keysym.sym == SDLK_F2 ) { screen = SDL_SetVideoMode( WINDOWWIDTH, WINDOWHEIGHT, 32, SDL_RESIZABLE | SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_HWPALETTE | SDL_ASYNCBLIT | SDL_HWACCEL ); }  
                   else { keys[event.key.keysym.sym]=true; }
               }
     	       if ( event.type == SDL_KEYUP )
	              keys[event.key.keysym.sym]=false;
	       if ( event.type == SDL_MOUSEMOTION )
	       {
                  mousex=event.motion.x;
                  mousey=event.motion.y;
                   
                  SLX_UpdateMouse(mousex, mousey);
               } 
               if ( event.type == SDL_MOUSEBUTTONDOWN )
	       {
                  mouseleft=(event.button.button==SDL_BUTTON_LEFT);
	          mouseright=(event.button.button==SDL_BUTTON_RIGHT);

                  SLX_UpdateMouseClick(mouseleft, mouseright);
               }
               if ( event.type == SDL_MOUSEBUTTONUP )
               {
	          mouseleft = (event.button.button!=SDL_BUTTON_LEFT);
	          mouseright = (event.button.button!=SDL_BUTTON_RIGHT);
                  
                  SLX_UpdateMouseClick(mouseleft, mouseright);
               }
        }

        //timeFrame = SDL_GetTicks() - clock; 
        //clock = SDL_GetTicks();
           
        //delayTime = (singleFrame - timeFrame);
        //if (delayTime > 0) { SDL_Delay(delayTime); }
        }
    }
    } while (f_restart != 0);

    SDL_Quit(); 
    
    return 0; 
} 

void DrawScene()
{
     

     /* vblank code */
     UpdateVScrollFullscreen(LONG(v_scrposy_dup,FFFFF618));     

     ReadJoypads(keys);
     palToCRAM();
     UpdateSpriteTable(v_spritetablebuf);
     UpdateHScrollTable(v_hscrolltablebuffer);
     writeVRAM(v_sgfx_buffer,0x2E0,0xF000/*vram_sonic*/);

     scrollflagBuf1 = v_bgscroll1;
     scrollflagBuf2 = v_bgscroll2;
     scrollflagBuf3 = v_bgscroll3;
     screenposxBuf1 = v_screenposx;
     screenposyBuf1 = v_screenposy;
     FFFFFF18 = FFFFF708;
     FFFFFF1C = FFFFF70C;
     FFFFFF20 = FFFFF710;
     FFFFFF24 = FFFFF714;
     FFFFFF28 = FFFFF718;
     FFFFFF2C = FFFFF71C;

     LoadTilesAsYouMove();
     AnimateLevelGfx();
     HUD_Update();

     //bsr.w	sub_1642        for pattern load cues distributed over vblanks
     /*------------*/

     //SLX_S1DebugInfo();   //not part of normal code, prints debug text of values to tiles
     
     //tst.b	(v_vbla_routine).w
     //beq.s	VBla_00
     //move.w	(vdp_control_port).l,d0
     //move.l	#$40000010,(vdp_control_port).l
     //move.l	(v_scrposy_dup).w,(vdp_data_port).l ; send screen y-axis pos. to VSRAM
     //btst	#6,(v_megadrive).w ; is Megadrive PAL?
     //beq.s	@notPAL		; if not, branch
     //move.w	#$700,d0
     //@waitPAL:
     //dbf	d0,@waitPAL
     //@notPAL:
     //move.b	(v_vbla_routine).w,d0
     //move.b	#0,(v_vbla_routine).w
     //move.w	#1,(f_hbla_pal).w
     //andi.w	#$3E,d0
     //move.w	VBla_Index(pc,d0.w),d0
     //jsr	VBla_Index(pc,d0.w)
     //VBla_Music:				; XREF: VBla_00
     //jsr	UpdateMusic
     //VBla_Exit:				; XREF: VBla_08
     //addq.l	#1,(v_vbla_count).w
     v_vbla_count = v_vbla_count + 1;
     videoToSurfaceExt(screen);
 
     SDL_Flip(screen);
}


void WaitForVBla()
{
    timeFrame = SDL_GetTicks() - clock; 
    clock = SDL_GetTicks();
           
    delayTime = (singleFrame - timeFrame);
    if (delayTime > 0) { SDL_Delay(delayTime); }

    DrawScene();     //replace with vblank routine
}

